<template>
  <div>
    <el-dialog
      :visible.sync="functionModal"
      :fullscreen="true"
      append-to-body
      :before-close="close"
      style="border-radius: 20px 20px 0px 0px;"
      >
      <span slot="title" style="padding-left:35px">
        <div style="position:absolute;top:15px" v-fileSvg="fileName"></div>
        {{ fileName }}
      </span>
      <!-- 文档word、excel、pdf -->
      <iframe frameborder="0" v-if="type === 1" :src="fileUrl" width="100%" :height="iframeHeight"></iframe>
      <!-- txt文件 -->
      <el-alert v-if="type === 2" type="warning" show-icon :closable="false">
        <span slot="title">如果遇到文件显示乱码，请尝试切换文件编码
          <el-select v-model="value" placeholder="请选择" size="mini" style="margin-left:5px;width:100px;" @change="readTxt">
              <el-option
              v-for="item in options"
              :key="item.value"
              :label="item.value"
              :value="item.value">
              </el-option>
          </el-select>
        </span>
      </el-alert>
      <div style="margin-top: 16px" v-show="type === 2" class="txtField" v-html="txtFile"></div>
      <!-- 图片 -->
      <div v-if="type === 3 && fileUrl" class="imgDiv">
        <image-preview v-if="functionModal && status ==='success'" :imgSrc="fileUrl"></image-preview>
        <img :src="fileUrl" v-if="status !== 'success'"/>
      </div>
      <!-- 视频音频 -->
      <div v-if="type === 4" class="imgDiv">
        <video :src="fileUrl" controls/>
      </div>
      <div class="publicBtn">
        <el-button size="mini" type="danger" @click="reload" v-if="hasError">重新加载</el-button>
        <el-button size="mini" v-download.prevent="[href, fileName]">下载</el-button>
        <el-button size="mini" type="primary" @click="close">关闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script lang="ts">
/**
 * 文件预览组件
 * 调用方法 preview (fileName: string, href: string)
 * 文档支持doc、docx、xls、xlsx
 * 支持pdf
 * 图片支持png、jpg、jpeg、gif、bmp
 * 文件支持txt
 */
import { Component, Vue, Watch } from 'vue-property-decorator';
import { globalToolModule } from './index'
import Axios from 'axios';
import ImagePreview from './imagePreview.vue'
// 文档预览地址前缀
const wordUrl = 'https://view.officeapps.live.com/op/view.aspx?src='
@Component({
  name: 'FilePreview',
  components: { ImagePreview }
})
export default class FilePreview extends Vue {
  [x: string]: any
  private iframeHeight: string = ''
  private fileName = '' // 文件名
  private href = '' // 真实地址，下载使用
  private fileUrl: string = '' // 转换的文档地址
  private functionModal: boolean = false
  private txtFile: string = '' // txt文件的内容
  private type: number = 1 // 文档类型 1：文档；2：txt文件；3：图片；4：视频，音频
  private value: string = 'utf-8' // txt文件编码
  private options: any = [
    {
      value: 'gb2312'
    },
    {
      value: 'utf-8'
    }
  ]

  private binaryData: any = [] // txt文件二进制
  // 图片、txt加载中占位
  private imageLoading = require('@/assets/img/webchatLoading.gif')
  // 图片、txt加载失败占位
  private imageError = require('@/assets/img/reply_error.png')
  // 加载失败时显示重新加载按钮
  private hasError = false
  // 加载状态：loading、success、error
  private status = 'loading'

  get previewDialog () {
    return globalToolModule.previewDialog
  }

  @Watch('previewDialog')
  private previewDialogChange (val) {
    if (val) {
      this.preview(globalToolModule.previewFile[0], globalToolModule.previewFile[1])
    }
  }

  private close () {
    this.binaryData = []
    this.fileUrl = ''
    this.functionModal = false
    this.txtFile = ''
    this.hasError = false
    this.status = 'loading'
    globalToolModule.setPreviewDialog(false)
  }

  // 读取txt文件内容
  private readTxt () {
    const fileReader = new FileReader()
    fileReader.readAsText(new Blob(this.binaryData), this.value)
    fileReader.onload = (evt: any) => {
      const data = evt.target.result;
      this.txtFile = data.split('\n').join('<br>')
      this.type = 2
    }
    fileReader.onerror = () => {
      this.hasError = true
      this.$message.error('读取文件内容失败')
    }
  }

  // 预览
  private preview (fileName: string, href: string) {
    this.hasError = false
    this.fileName = fileName
    this.href = href
    const ext: any = fileName.split('.').pop()?.toLowerCase()
    this.iframeHeight = document.documentElement.clientHeight - 135 + 'px'
    if (ext === 'pdf') {
      this.fileUrl = href
      this.type = 1
      this.functionModal = true
    } else if (['doc', 'docx', 'xls', 'xlsx'].includes(ext)) {
      this.fileUrl = wordUrl + href
      this.type = 1
      this.functionModal = true
    } else if (ext === 'txt') {
      this.type = 3
      this.fileUrl = this.imageLoading
      this.functionModal = true
      Axios.get(this.href, {
        responseType: 'arraybuffer'
      }).then(res => {
        this.binaryData.push(res.data)
        this.readTxt()
      }).catch(() => {
        this.hasError = true
        this.$message.error('在线预览失败')
        this.fileUrl = this.imageError
      })
    } else if (['png', 'jpg', 'gif', 'jpeg', 'bmp'].includes(ext)) {
      this.loadImg(href)
      this.type = 3
      this.functionModal = true
    } else if (['mp3', 'mp4'].includes(ext)) {
      this.fileUrl = href
      this.type = 4
      this.functionModal = true
    }
  }

  // 图片加载
  private loadImg (url) {
    this.status = 'loading'
    this.fileUrl = this.imageLoading
    const img = document.createElement('img')
    img.src = url
    img.onload = () => {
      this.status = 'success'
      this.fileUrl = url
    }
    img.onerror = () => {
      this.status = 'error'
      this.hasError = true
      this.fileUrl = this.imageError
      this.$message.error('图片加载失败')
    }
  }

  // 重新加载
  private reload () {
    this.preview(this.fileName, this.href)
  }

  // 下载文件
  private downloadFile () {
    const a: any = document.createElement('a')
    a.href = this.href
    a.download = ''
    a.style.opacity = 0
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  }
}
</script>

<style lang="stylus" scoped>
.txtField
  overflow: auto;
  min-height: 300px;
  max-height: 450px;
  border: 1px solid $c-main;
  border-radius: 4px;
  padding: 10px;
  font-size: 14px;
  line-height: 25px;
  clear: both;
.imgDiv
  width calc(100% - 48px)
  position absolute
  height: calc(100% - 110px)
  overflow: auto
  top 50px
  img
    height: 100%;
    width: 100%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    object-fit: scale-down;
  video
    max-height: 100%;
    max-width: 100%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    object-fit: scale-down;
.publicBtn
  width calc(100% - 48px)
  position absolute
  bottom 0px
  height 56px
  line-height 56px
  background #fff
  text-align right
  z-index 100
</style>
